package task

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"pids-cloud-server/constants"
	"pids-cloud-server/entity"
	"pids-cloud-server/logging"
	"sync"
	"time"

	"pids-cloud-server/utils"

	"github.com/google/uuid"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

func UrlHealthCheckTask() {
	logging.Info("---------定时监测接口服务任务开始---------")
	start := time.Now()

	// 获取数据库连接
	db := utils.GetDB()
	if db == nil {
		logging.Error("数据库连接失败，跳过接口健康检查任务")
		return
	}

	getExsistInterfaceAlarmList(db)
	//获取数据库中的接口监测地址列表
	var interfaceInfos []entity.InterfaceInfo
	err := db.Model(&entity.InterfaceInfo{}).Find(&interfaceInfos).Error
	if err != nil {
		logging.Error("获取接口监测地址列表失败！", err)
		return
	}
	workerCount := 10 // 限制最多 10 个并发 worker
	jobChannel := make(chan entity.InterfaceInfo, len(interfaceInfos))
	interfaceChannel := make(chan entity.InterfaceInfo, len(interfaceInfos))
	alarmChannel := make(chan entity.AlarmInfo, len(interfaceInfos))
	var wg sync.WaitGroup
	// 启动 worker 处理接口监测
	for i := 0; i < workerCount; i++ {
		wg.Add(1)
		go processInterface(jobChannel, interfaceChannel, alarmChannel, &wg)
	}
	// 将任务发送到 jobChannel
	for _, interfaceInfo := range interfaceInfos {
		jobChannel <- interfaceInfo
	}
	close(jobChannel)
	// 等待所有 goroutine 完成后关闭 channel
	go func() {
		wg.Wait()
		close(interfaceChannel)
		close(alarmChannel)
	}()
	//收集所有的接口信息
	var allInterfaceInfos []entity.InterfaceInfo
	var allAlarms []entity.AlarmInfo
	for interfaceInfo := range interfaceChannel {
		interfaceInfo.UpdateTime = time.Now()
		allInterfaceInfos = append(allInterfaceInfos, interfaceInfo)
	}
	//更新或新增接口信息数据表
	if err = UpsertInterfaceInfo(db, allInterfaceInfos); err != nil {
		logging.Error("批量更新接口信息失败！", err)
	} else {
		logging.Info("Upsert interface信息success！")
	}
	for alarmInfo := range alarmChannel {
		allAlarms = append(allAlarms, alarmInfo)
	}
	//保存、更新告警数据
	if len(allAlarms) > 0 {
		tx := db.Clauses(clause.OnConflict{
			Columns:   []clause.Column{{Name: "id"}},
			DoUpdates: clause.AssignmentColumns([]string{"status", "modify_time", "level_id", "detail"}),
		}).CreateInBatches(&allAlarms, 100)
		if tx.Error != nil {
			logging.Error("保存接口服务告警数据失败：" + tx.Error.Error())
		}
	}
	logging.Info("定时监测接口服务任务结束---------耗时：", time.Since(start))
}

// 检测单个接口
func processInterface(jobChannel <-chan entity.InterfaceInfo, interfaceChannel chan<- entity.InterfaceInfo, alarmChannel chan<- entity.AlarmInfo, wg *sync.WaitGroup) {
	defer wg.Done()
	client := &http.Client{
		Timeout: 5 * time.Second, // 设定超时时间
	}
	for interfaceInfo := range jobChannel {
		// 调用单独的方法处理单个接口
		result, alarmInfo := processSingleInterface(client, interfaceInfo)

		// 存入结果通道
		interfaceChannel <- result

		// 如果有告警信息，则存入告警通道
		if alarmInfo != nil {
			alarmChannel <- *alarmInfo
		}
	}
}

// 新增方法：处理单个接口
func processSingleInterface(client *http.Client, interfaceInfo entity.InterfaceInfo) (entity.InterfaceInfo, *entity.AlarmInfo) {
	var alarmInfo *entity.AlarmInfo
	httpRequestStart := time.Now()

	resp, err := client.Get(interfaceInfo.Url)
	if err != nil {
		logging.Errorf("接口 %s 访问失败: %v", interfaceInfo.Url, err)
		alarmInfo = generateInterfaceAlarm(interfaceInfo, "接口访问失败")
		return interfaceInfo, alarmInfo
	}
	defer resp.Body.Close() // 这个 defer 会在 processSingleInterface 方法结束时执行

	duration := time.Since(httpRequestStart)
	interfaceInfo.ResponseTime = duration.Milliseconds()

	if resp.StatusCode != http.StatusOK {
		logging.Errorf("接口 %s 返回状态码: %d", interfaceInfo.Url, resp.StatusCode)
		alarmInfo = generateInterfaceAlarm(interfaceInfo, fmt.Sprintf("接口返回状态码 %d 非 200", resp.StatusCode))
	} else {
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Printf("接口 %s 读取响应失败: %v", interfaceInfo.Url, err)
			alarmInfo = generateInterfaceAlarm(interfaceInfo, "接口响应读取失败")
		} else {
			// 解析 JSON 响应
			var result map[string]interface{}
			if err := json.Unmarshal(body, &result); err != nil {
				log.Printf("接口 %s JSON 解析失败: %v", interfaceInfo.Url, err)
				alarmInfo = generateInterfaceAlarm(interfaceInfo, "接口 JSON 解析失败")
			} else {
				// 进行规则匹配
				value, exists := result[interfaceInfo.CheckField]
				if !exists {
					logging.Errorf("接口 %s 响应缺少字段: %s", interfaceInfo.Url, interfaceInfo.CheckField)
					alarmInfo = generateInterfaceAlarm(interfaceInfo, fmt.Sprintf("缺少字段: %s", interfaceInfo.CheckField))
				} else if fmt.Sprintf("%v", value) != interfaceInfo.ExpectedValue {
					logging.Errorf("接口 %s 校验失败: %s 期望 %v, 但返回 %v", interfaceInfo.Url, interfaceInfo.CheckField, interfaceInfo.ExpectedValue, value)
					alarmInfo = generateInterfaceAlarm(interfaceInfo, fmt.Sprintf("字段 %s 期望 %v, 但返回 %v", interfaceInfo.CheckField, interfaceInfo.ExpectedValue, value))
				} else {
					logging.Infof("接口 %s 检测通过", interfaceInfo.Url)
					alarmInfo = recoverInterfaceAlarm(interfaceInfo)
				}
			}
		}
	}

	return interfaceInfo, alarmInfo
}

// 恢复告警记录
func recoverInterfaceAlarm(interfaceInfo entity.InterfaceInfo) (alarmInfo *entity.AlarmInfo) {
	value, exists := constants.INTERFACE_ALARM_INFO_MAP.Load(interfaceInfo.Url)
	//存在旧告警，且没有产生新告警时
	if exists {
		// 接口服务 变正常，删除告警，并生成恢复告警
		logging.Infof("接口 %s:%s 恢复正常, 清除告警", interfaceInfo.Url, interfaceInfo.InterfaceName)
		if alarmValue, ok := value.(entity.AlarmInfo); ok {
			alarmInfo = &alarmValue // 取地址
		} else {
			return nil // 避免 panic
		}
		alarmInfo.Status = entity.INACTIVE
		alarmInfo.ModifyTime = time.Now()
		constants.INTERFACE_ALARM_INFO_MAP.Delete(interfaceInfo.Url)
	}
	return alarmInfo
}

func UpsertInterfaceInfo(db *gorm.DB, interfaceInfos []entity.InterfaceInfo) error {
	// 插入或更新操作
	err := db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "url"}},                                              // 唯一约束字段
		DoUpdates: clause.AssignmentColumns([]string{"state", "response_time", "update_time"}), // 要更新的字段
	}).CreateInBatches(&interfaceInfos, 100).Error
	return err
}

// 查询数据库中已经存在的接口异常告警数据
func getExsistInterfaceAlarmList(db *gorm.DB) (alarmInfoList []entity.AlarmInfo) {
	if tx := db.Where("status = ? AND type = ?", entity.ACTIVE, entity.INTERFACE_ERROR).Find(&alarmInfoList); tx.Error == nil {
		for _, alarmInfo := range alarmInfoList {
			constants.INTERFACE_ALARM_INFO_MAP.Store(alarmInfo.ResourceId, alarmInfo)
		}
	} else {
		logging.Error("初始化接口服务告警数据失败,退出服务！", tx.Error)
		return nil
	}
	return alarmInfoList
}
func generateInterfaceAlarm(interfaceInfo entity.InterfaceInfo, reason string) (alarmInfo *entity.AlarmInfo) {
	value, exists := constants.INTERFACE_ALARM_INFO_MAP.Load(interfaceInfo.Url)
	if exists {
		//当前接口服务存在告警记录，则更新告警记录
		if alarmValue, ok := value.(entity.AlarmInfo); ok {
			alarmInfo = &alarmValue // 取地址
		} else {
			return nil // 避免 panic
		}
		alarmInfo.Detail = interfaceInfo.InterfaceName + ":" + interfaceInfo.Url + "异常:" + reason
		alarmInfo.ModifyTime = time.Now()
		constants.INTERFACE_ALARM_INFO_MAP.Store(interfaceInfo.Url, alarmInfo)
	} else {
		//当前接口服务不存在告警记录，则新增告警记录
		alarmInfo = &entity.AlarmInfo{
			ID:         uuid.NewString(),
			Type:       entity.INTERFACE_ERROR,
			Detail:     interfaceInfo.InterfaceName + ":" + interfaceInfo.Url + "异常:" + reason,
			HostIP:     interfaceInfo.IP,
			ResourceId: interfaceInfo.Url,
			Flag:       entity.Server,
			Status:     entity.ACTIVE,
			LevelID:    1,
			CreateTime: time.Now(),
			ModifyTime: time.Now(),
		}
		constants.INTERFACE_ALARM_INFO_MAP.Store(interfaceInfo.Url, alarmInfo)
	}
	return alarmInfo
}
